﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;

namespace CPPEI.Coolzon.UI
{
    [XPartIcon("pack://application:,,,/CPPEI.Coolzon.UI;component/Images/PartIcons/容器组件.png")]
    [XPart("Panel", "容器组件")]
    [System.ComponentModel.DisplayName("容器组件")]
    public partial class PanelPart : ControlPart, IPartContainer
    {
        private PartCollection _partCollection;

        private Canvas _canvas;

        public PanelPart()
        {
            _partCollection = new PartCollection(this);
            _canvas = new Canvas();
            //_canvas.Background = new SolidColorBrush(Colors.Yellow);
            this.Content = _canvas;
        }

        protected void SetPartLeft(Part part)
        {

        }

        public void SetPartTop(Part part)
        {
        }

        public void RemovePart(Part part)
        {
        }

        #region override 
        

        protected override void OnInit(PartContext context)
        {
            for (int index = 0; index < _partCollection.Count; index++)
            {
                _partCollection[index].Init(context);
            }
            base.OnInit(context);
        }

        protected override void OnActive(PartContext context)
        {
            for (int index = 0; index < _partCollection.Count; index++)
            {
                _partCollection[index].Active(context);
            }
            base.OnActive(context);
        }

        protected override void OnDeactive(PartContext context)
        {
            for (int index = 0; index < _partCollection.Count; index++)
            {
                _partCollection[index].Deactive();
            }

            base.OnDeactive(context);
        }

        protected override void OnDestory()
        {
            for (int index = 0; index < _partCollection.Count; index++)
            {
                _partCollection[index].Destory();
            }

            // 移除引用
            for (int index = 0; index < _partCollection.Count; index++)
            {
                _canvas.Children.Remove(_partCollection[index]);

                _partCollection[index].ParentPart = null;
            }
            _partCollection.Clear();

            base.OnDestory();
        }

        protected override void OnReset()
        {
            base.OnReset();
            for (int index = 0; index < this._partCollection.Count; index++)
            {
                this._partCollection[index].Reset();
            }
        }
        protected override void OnRefresh()
        {
            base.OnRefresh();
            if(_partCollection == null)
            {
                return;
            }
            for (int index = 0; index < _partCollection.Count; index++)
            {
                _partCollection[index].Refresh();
            }
        }

        public override void VisibleRegionChange(Point ltPtOfView, Point rbPtOfView)
        {
            for (int index = 0; index < this._partCollection.Count; index++)
            {
                this._partCollection[index].VisibleRegionChange(ltPtOfView, rbPtOfView);
            }

            base.VisibleRegionChange(ltPtOfView, rbPtOfView);
        }

        public override UI.Part GetPartAtPoint(Type type, Point pointInRoot, UIElement rootElement)
        {
            if (!XIsVisible)
            {
                return null;
            }
            UI.Part part = null;
            // Point absolutePoint = this.TranslatePoint(new Point(0, 0), rootElement);
            for (int index = 0; index < this._partCollection.Count; index++)
            {
                part = this._partCollection[index].GetPartAtPoint(type, pointInRoot, rootElement);
                if (part != null)
                {
                    return part;
                }
            }
            return base.GetPartAtPoint(type, pointInRoot, rootElement);
        }


        /// <summary>
        /// 测试是否x，y点是否命中了组件实例
        /// </summary>
        /// <param name="pointInScene">场景中的坐标点</param>
        /// <returns></returns>
        public override Data.XHitResult XHitTest(Point pointInScene)
        {
            if (!XIsVisible)
            {
                return new Data.XHitResult(false, null, default(Point));
            }

            Point pos = this.XGetAbsolutePos();
            Size size = this.XGetSize();

            if (pointInScene.X >= pos.X
                && pointInScene.Y >= pos.Y
                && pointInScene.X <= pos.X + size.Width
                && pointInScene.Y <= pos.Y + size.Height)
            {
                for (int index = this._partCollection.Count - 1; index >= 0; index--)
                {
                    Data.XHitResult hitResult = this._partCollection[index].XHitTest(pointInScene);
                    if (hitResult.IsSuccess)
                    {
                        return hitResult;
                    }
                }
                return new Data.XHitResult(true, this, new Point(pointInScene.X - pos.X, pointInScene.Y - pos.Y));
            }
            return new Data.XHitResult(false, null, default(Point));
        }

        /// <summary>
        /// 测试是否x，y点是否命中了组件实例
        /// </summary>
        /// <typeparam name="T">命中的组件必须属于这个类型</typeparam>
        /// <param name="pointInScene">场景中的坐标点</param>
        /// <returns></returns>
        public override Data.XHitResult XHitTest<T>(Point pointInScene)
        {
            if (!XIsVisible)
            {
                return new Data.XHitResult(false, null, default(Point));
            }

            Type type = typeof(T);
            Point pos = this.XGetAbsolutePos();
            Size size = this.XGetSize();

            if (pointInScene.X >= pos.X
                && pointInScene.Y >= pos.Y
                && pointInScene.X <= pos.X + size.Width
                && pointInScene.Y <= pos.Y + size.Height)
            {
                for (int index = this._partCollection.Count - 1; index >= 0; index--)
                {
                    Data.XHitResult hitResult = this._partCollection[index].XHitTest<T>(pointInScene);
                    if (hitResult.IsSuccess)
                    {
                        return hitResult;
                    }
                }
                if (this.GetType() == type || this.GetType().IsSubclassOf(type)
                    || type.IsAssignableFrom(this.GetType()))
                {
                    return new Data.XHitResult(true, this, new Point(pointInScene.X - pos.X, pointInScene.Y - pos.Y));
                }
            }
            return new Data.XHitResult(false, null, default(Point));
        }

        public Point XGetContentPos()
        {
            return new Point(this.Padding.Left, this.Padding.Top);
        }

        #endregion

        #region Implement IPartContainer

        public List<Part> GetPartList()
        {
            return _partCollection.PartList;
        }

        /// <summary>
        /// 添加子组件
        /// </summary>
        /// <param name="part"></param>
        public void AddPart(Part part)
        {
            if (ValidateChildType(part.GetType()))
            {
                _partCollection.Add(part);

                _canvas.Children.Add(part);
                Canvas.SetZIndex(part, _canvas.Children.Count - 1);

                Canvas.SetLeft(part, part.XLeft);
                Canvas.SetTop(part, part.XTop);

                part.ParentPart = this;
            }
        }

        public void XRemovePart(Part part)
        {
            _partCollection.Remove(part);

            _canvas.Children.Remove(part);
        }

        /// <summary>
        /// 获取子组件
        /// </summary>
        /// <param name="partName"></param>
        /// <param name="isRecursive">是否递归</param>
        /// <returns></returns>
        public Part GetChildPart(string partName, bool isRecursive)
        {
            return _partCollection.GetChildPart(partName, isRecursive);
        }

        /// <summary>
        /// 根据类型来获取组件里包含的子组件
        /// </summary>
        /// <param name="isRecursive"></param>
        /// <returns></returns>
        public List<T> GetChildPartByType<T>(bool isRecursive)
        {
            return _partCollection.GetChildPartByType<T>(isRecursive);
        }

        public bool ValidateChildType(Type childType)
        {
            if (childType == typeof(AreaPart) || childType.IsSubclassOf(typeof(AreaPart)))
            {
                return true;
            }
            else if (childType.IsSubclassOf(typeof(ControlPart)))
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// 获取实际的可存放组件的容器控件
        /// </summary>
        /// <returns></returns>
        public UIElement GetContentContainer()
        {
            return this._canvas;
        }

        public void BringPartTo(Part part, int index)
        {
            XRemovePart(part);
            
            _partCollection.Insert(part, index);

            _canvas.Children.Insert(index, part);
            Canvas.SetZIndex(part, index);

            Canvas.SetLeft(part, part.XLeft);
            Canvas.SetTop(part, part.XTop);

            part.ParentPart = this;
        }

        public int GetPartIndex(Part part)
        {
            if (part != null)
            {
                if (_partCollection != null && _partCollection.Count > 0)
                {
                    for (int index = 0; index < _partCollection.Count; index++)
                    {
                        if (_partCollection[index] == part)
                        {
                            return index;
                        }
                    }
                }
            }
            return -1;
        }

        public int GetSendToBackIndex(Part part)
        {
            return 0;
        }

        public int GetBringToFrontIndex(Part part)
        {
            return _partCollection.Count - 1;
        }
        public int GetForwardIndex(Part part)
        {
            int index = GetPartIndex(part);
            return index < _partCollection.Count - 1 ? index + 1 : index;
        }

        public int GetBackwardIndex(Part part)
        {
            int index = GetPartIndex(part);
            return index > 0 ? index - 1 : index;
        }

        public Tuple<Point?, Point?, byte> GetAlignLinePoint(Part part, double left = -1, double top = -1, double right = -1, double bottom = -1)
        {
            //00表示left和top，01表示right和top，10表示left和bottom，11表示right和bottom
            byte bDirection = 0;
            Point? leftOrRight = null;
            Point? topOrBottom = null;
            double minOffsetX = double.MaxValue;
            double minOffsetY = double.MaxValue;
            for (int index = 0; index < _partCollection.Count; index++)
            {
                Part destPart = _partCollection[index];
                if (destPart != part)
                {
                    if (left >= 0)
                    {
                        if (Math.Abs(destPart.XLeft - left) < 2 && Math.Abs(destPart.XLeft - left) < minOffsetX)
                        {
                            minOffsetX = Math.Abs(destPart.XLeft - left);
                            leftOrRight = new Point(destPart.XLeft, destPart.XTop + destPart.XHeight / 2);
                            bDirection &= 2;
                        }
                        else if (Math.Abs(destPart.XLeft + destPart.XWidth - left) < 2 && Math.Abs(destPart.XLeft + destPart.XWidth - left) < minOffsetX)
                        {
                            minOffsetX = Math.Abs(destPart.XLeft + destPart.XWidth - left);
                            leftOrRight = new Point(destPart.XLeft + destPart.XWidth, destPart.XTop + destPart.XHeight / 2);
                            bDirection &= 2;
                        }
                    }
                    if (top >= 0)
                    {
                        if (Math.Abs(destPart.XTop - top) < 2 && Math.Abs(destPart.XTop - top) < minOffsetY)
                        {
                            minOffsetY = Math.Abs(destPart.XTop - top);
                            topOrBottom = new Point(destPart.XLeft + destPart.XWidth / 2, destPart.XTop);
                            bDirection &= 1;
                        }
                        else if (Math.Abs(destPart.XTop + destPart.XHeight - top) < 2 && Math.Abs(destPart.XTop + destPart.XHeight - top) < minOffsetY)
                        {
                            minOffsetY = Math.Abs(destPart.XTop + destPart.XHeight - top);
                            topOrBottom = new Point(destPart.XLeft + destPart.XWidth / 2, destPart.XTop + destPart.XHeight);
                            bDirection &= 1;
                        }
                    }
                    if (right >= 0)
                    {
                        if (Math.Abs(destPart.XLeft - right) < 2 && Math.Abs(destPart.XLeft - right) < minOffsetX)
                        {
                            minOffsetX = Math.Abs(destPart.XLeft - right);
                            leftOrRight = new Point(destPart.XLeft, destPart.XTop + destPart.XHeight / 2);
                            bDirection |= 1;
                        }
                        else if (Math.Abs(destPart.XLeft + destPart.XWidth - right) < 2 && Math.Abs(destPart.XLeft + destPart.XWidth - right) < minOffsetX)
                        {
                            minOffsetX = Math.Abs(destPart.XLeft + destPart.XWidth - right);
                            leftOrRight = new Point(destPart.XLeft + destPart.XWidth, destPart.XTop + destPart.XHeight / 2);
                            bDirection |= 1;
                        }
                    }
                    if (bottom >= 0)
                    {
                        if (Math.Abs(destPart.XTop - bottom) < 2 && Math.Abs(destPart.XTop - bottom) < minOffsetY)
                        {
                            minOffsetY = Math.Abs(destPart.XTop - bottom);
                            topOrBottom = new Point(destPart.XLeft + destPart.XWidth / 2, destPart.XTop);
                            bDirection |= 2;
                        }
                        else if (Math.Abs(destPart.XTop + destPart.XHeight - bottom) < 2 && Math.Abs(destPart.XTop + destPart.XHeight - bottom) < minOffsetY)
                        {
                            minOffsetY = Math.Abs(destPart.XTop + destPart.XHeight - bottom);
                            topOrBottom = new Point(destPart.XLeft + destPart.XWidth / 2, destPart.XTop + destPart.XHeight);
                            bDirection |= 2;
                        }
                    }
                }
            }
            return new Tuple<Point?, Point?, byte>(leftOrRight, topOrBottom, bDirection);
        }
        #endregion
    }
}
